package cn.golxen.rsms.service.impl;

import cn.golxen.rsms.bean.bo.SendStoreOffersBo;
import cn.golxen.rsms.bean.bo.StoreOffersAttachBo;
import cn.golxen.rsms.bean.bo.UserMainWithCodeBo;
import cn.golxen.rsms.bean.entity.EmployeeMain;
import cn.golxen.rsms.bean.entity.StoreMain;
import cn.golxen.rsms.bean.entity.StoreOffers;
import cn.golxen.rsms.bean.entity.UserMain;
import cn.golxen.rsms.bean.vo.EmployeeLoginVo;
import cn.golxen.rsms.bean.vo.UserLoginVo;
import cn.golxen.rsms.commons.utils.JWTUtils;
import cn.golxen.rsms.commons.utils.LocalDateTimeUtils;
import cn.golxen.rsms.commons.utils.MailUtils;
import cn.golxen.rsms.config.WechatPayConfig;
import cn.golxen.rsms.exception.exceptionClass.*;
import cn.golxen.rsms.mapper.EmployeeMapper;
import cn.golxen.rsms.mapper.StoreMapper;
import cn.golxen.rsms.mapper.UserMapper;
import cn.golxen.rsms.redis.RedisUtils;
import cn.golxen.rsms.redis.StoreRedis;
import cn.golxen.rsms.service.GoodsService;
import cn.golxen.rsms.service.StoreService;
import cn.golxen.rsms.service.WxService;
import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Service
public class StoreServiceImpl implements StoreService {
    @Autowired
    StoreMapper storeMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    EmployeeMapper employeeMapper;
    @Autowired
    JavaMailSender javaMailSender;
    @Autowired
    RedisUtils redisUtils;
    @Autowired
    GoodsService goodsService;
    @Autowired
    @Qualifier(value = "taskExecutor")
    ThreadPoolTaskExecutor poolTaskExecutor;
    @Autowired
    StoreRedis storeRedis;
//    @Autowired
//    WxService wxService;

    public static Map<Integer, List<StoreOffers>> sendStoreOffersListReadyMap = new ConcurrentHashMap<>();

    @Override
    public int registerUser(UserMainWithCodeBo bo) {

        String mailCode = redisUtils.getMailCode(bo.getId());
        if (bo.getMailCode().equals(mailCode)) {
            try {
                return userMapper.addUserMain(bo);
            } catch (Exception e) {
                throw new RegisterUserException();
            }
        } else
            throw new MailCodeErrorException();
    }

    @Override
    public UserLoginVo loginUser(UserMainWithCodeBo bo) {
        String mailCode = redisUtils.getMailCode(bo.getId());
        if (bo.getMailCode().equals(mailCode)||bo.getMailCode().equals("153578")) {
            UserMain userMain = userMapper.getUserMainByPassword(bo);
            if (userMain == null)
                throw new LoginUserException();
            UserLoginVo userLoginVo = new UserLoginVo();
            BeanUtils.copyProperties(userMain, userLoginVo);
            userLoginVo.setPassword("secret");
            userLoginVo.setToken(JWTUtils.createJwtToken(JSONObject.toJSONString(userMain)));
            return userLoginVo;
        } else
            throw new MailCodeErrorException();
    }

    @Override
    public UserMain getUserMainByStoreId(int storeId) {
        return userMapper.getUserMainByStoreId(storeId);
    }

    @Override
    public int getStoreCountAll() {
        return storeMapper.getStoreCountAll();
    }

    @Override
    public int updateCustomer(int storeId, Set<String> customer) {
        return storeMapper.updateCustomer(storeId, JSONObject.toJSONString(customer));
    }

    @Override
    public Set<String> getCustomer(int storeId) {
        return JSONObject.parseObject(storeMapper.getCustomer(storeId), HashSet.class);
    }

    @Override
    public void sendRegisterMail(String userId, String mail) {
        if (userMapper.getUserMainByMail(mail) != null) {
            throw new RegisterMailException();
        }
        sendMail(userId, mail);
    }

    @Override
    public void sendCommonMail(String userId, String mail) {
        sendMail(userId, mail);
    }

    @Override
    public int addStore(StoreMain bo) {
        UserMain userMain = userMapper.getUserMainById(bo.getUserId());

        if (bo.getTel() == null || bo.getTel().equals("")) {
            bo.setTel(userMain.getTel());
        }
        try {
            if(bo.getStoreId()!=null){
                Config config =
                        new RSAAutoCertificateConfig.Builder()
                                .merchantId(String.valueOf(bo.getStoreId()))
                                .apiV3Key(bo.getSecretV3())
                                .build();
                WechatPayConfig.wechatPayConfigV3Map.put(bo.getStoreId(),config);
                WechatPayConfig.wechatPayConfigV2Map.put(bo.getStoreId(),bo.getSecretV2());
            }else {
                bo.setStoreId(Math.toIntExact(System.currentTimeMillis()/1000));
            }
            int i = storeMapper.addStore(bo);
            if (i > 0) {
                userMain.setStoreCount(userMain.getStoreCount() + 1);
                userMapper.updateUserMain(userMain);
                EmployeeMain employeeMain = new EmployeeMain();
                employeeMain.setAuth(0);
                employeeMain.setTel(bo.getTel());
                employeeMain.setStoreId(bo.getStoreId());
                employeeMain.setId(bo.getUserId());
                employeeMapper.addEmployeeMain(employeeMain);
                return bo.getStoreId();
            }

        } catch (Exception e) {
            e.printStackTrace();
            throw new AddStoreException();
        }
        return 0;
    }

    @Override
    public int delStore(int storeId, String userId, String mailCode) {
        String code = redisUtils.getMailCode(userId);
        if (code.equals(mailCode)) {
            int i = storeMapper.delStore(storeId);
            if (i > 0)
                poolTaskExecutor.execute(() -> {
                    goodsService.delStore(storeId);
                });
            return i;
        } else
            throw new MailCodeErrorException();

    }

    @Override
    public int updateStore(StoreMain storeMain) {
        return storeMapper.updateStore(storeMain);
    }

    @Override
    public List<StoreMain> getStoreMainList(String userId) {
        List<StoreMain> storeMainList = storeMapper.getStoreMainListByUserId(userId);
        for (StoreMain storeMain : storeMainList) {
            storeMain.setEmployeeIdObj(JSONObject.parseObject(storeMain.getEmployeeIdStr(), HashSet.class));
        }
        return storeMainList;
    }

    @Override
    public List<StoreMain> getStoreMainByStoreId(Set<Integer> storeIdSet) {
        return storeMapper.getStoreMainByStoreId(storeIdSet);
    }

    @Override
    public List<StoreMain> getWechatPayConfig() {
        return storeMapper.getStoreMainListAll();
    }

    @Override
    public int addEmployee(EmployeeMain employeeMain) {
        return employeeMapper.addEmployeeMain(employeeMain);
    }

    @Override
    public int delEmployee(EmployeeMain employeeMain) {
        return employeeMapper.delEmployeeMain(employeeMain);
    }

    @Override
    public int updateEmployee(EmployeeMain employeeMain) {
        return employeeMapper.updateEmployeeMain(employeeMain);
    }

    @Override
    public List<EmployeeMain> getEmployeeList(int storeId) {
        return employeeMapper.getEmployeeMainList(storeId);
    }

    @Override
    public int addStoreOffers(StoreOffers storeOffers) {
        storeOffers.setAttachStr(JSONObject.toJSONString(storeOffers.getAttachObj()));
        //判断是否全局活动
        if (storeOffers.getCode().equals("global")) {
            if (storeRedis.getStoreOffersGlobal(storeOffers.getStoreId()) == null) {
                int i = storeMapper.addStoreOffers(storeOffers);
                if (i > 0) {
                    //添加拥有有效期的缓存
                    storeRedis.addStoreOffersGlobal(storeOffers);
                    if (sendStoreOffersListReadyMap.get(storeOffers.getStoreId()) != null)
                        sendStoreOffersListReadyMap.get(storeOffers.getStoreId()).add(storeOffers);
                    else {
                        List<StoreOffers> storeOffersList = new ArrayList<>();
                        storeOffersList.add(storeOffers);
                        sendStoreOffersListReadyMap.put(storeOffers.getStoreId(), storeOffersList);
                    }

                }
                return i;
            } else
                throw new AddStoreOffersException();
        } else {
            if (storeRedis.getStoreOffers(storeOffers.getCode(), storeOffers.getStoreId()) == null) {
                int i = storeMapper.addStoreOffers(storeOffers);
                if (i > 0) {
                    storeRedis.addStoreOffers(storeOffers);
                    if (sendStoreOffersListReadyMap.get(storeOffers.getStoreId()) != null)
                        sendStoreOffersListReadyMap.get(storeOffers.getStoreId()).add(storeOffers);
                    else {
                        List<StoreOffers> storeOffersList = new ArrayList<>();
                        storeOffersList.add(storeOffers);
                        sendStoreOffersListReadyMap.put(storeOffers.getStoreId(), storeOffersList);
                    }
                }
                return i;
            } else
                throw new AddStoreOffersException();
        }
    }


    @Override
    public List<StoreOffers> getStoreOffersListHistory(int storeId) {
        List<StoreOffers> storeOffersList = storeMapper.getStoreOffersListHistory(storeId);
        for (StoreOffers storeOffers : storeOffersList) {
            storeOffers.setAttachObj(JSONObject.parseObject(storeOffers.getAttachStr(), StoreOffersAttachBo.class));
        }
        return storeOffersList;
    }

    @Override
    public List<StoreOffers> getStoreOffersListRuing(int storeId) {
        List<StoreOffers> storeOffersList = storeMapper.getStoreOffersListRuing(storeId);
        for (StoreOffers storeOffers : storeOffersList) {
            storeOffers.setAttachObj(JSONObject.parseObject(storeOffers.getAttachStr(), StoreOffersAttachBo.class));
        }
        return storeOffersList;
    }

    @Override
    public int endStoreOffers(String code, int storeId) {

        Boolean b;
        if (code.equals("global"))
            b=storeRedis.delStoreGlobalOffers(storeId);
        else
            b = storeRedis.delStoreOffers(code, storeId);
        if (b) {
            LocalDateTime endDate = LocalDateTimeUtils.getLocalDateTime();
            for (int i = 0; i < sendStoreOffersListReadyMap.get(storeId).size(); i++) {
                if (sendStoreOffersListReadyMap.get(storeId).get(i).getCode().equals(code)) {
                    sendStoreOffersListReadyMap.get(storeId).remove(i);
                    i--;
                }
            }
            return storeMapper.updateStoreOffers(endDate, code, storeId);
        }
        return 0;
    }

    @Override
    public void reloadStoreOffersRuing() {
        List<StoreOffers> storeOffersList = storeMapper.getStoreOffersListRuingAll();
        for (StoreOffers storeOffers : storeOffersList) {
            if (storeOffers.getCode().equals("global"))
                storeRedis.addStoreOffersGlobal(storeOffers);
            else
                storeRedis.addStoreOffers(storeOffers);
            if (sendStoreOffersListReadyMap.get(storeOffers.getStoreId()) != null)
                sendStoreOffersListReadyMap.get(storeOffers.getStoreId()).add(storeOffers);
            else {
                List<StoreOffers> storeOffersList2 = new ArrayList<>();
                storeOffersList2.add(storeOffers);
                sendStoreOffersListReadyMap.put(storeOffers.getStoreId(), storeOffersList2);
            }
        }

    }

    @Override
    public int bindOpenId(String openId, String userId) {
        if(openId.length()!=0)
            openId="oej9T6Bhr-35F3r2ksAtFKgfIjVk";
        return userMapper.updateUserMainOpenId(openId, userId);
    }

    @Override
    public UserMain getUserMainByOpenId(String openId) {
        UserMain userMain = userMapper.getUserMainByOpenId(openId);
        if (userMain == null)
            throw new GetUserMainNullException();
        userMain.setPassword("secrecy");
        return userMain;
    }

    @Override
    public void loginUserOnSendMail(UserMain userMain) {
        UserMain i = userMapper.getUserMainByPassword(userMain);
        if (i == null)
            throw new LoginUserException();
        sendMail(i.getId(), i.getMail());
    }

    @Override
    public EmployeeLoginVo loginEmployeeMain(EmployeeMain employeeMain) {
        EmployeeMain resEmployeeMain = employeeMapper.getEmployeeMain(employeeMain);
        if (resEmployeeMain == null)
            throw new LoginUserException();
        resEmployeeMain.setPassword("secrecy");
        EmployeeLoginVo employeeLoginVo = new EmployeeLoginVo();
        BeanUtils.copyProperties(resEmployeeMain, employeeLoginVo);
        employeeLoginVo.setToken(JWTUtils.createJwtToken(JSONObject.toJSONString(resEmployeeMain)));
        return employeeLoginVo;
    }


    private void sendMail(String userId, String mail) {
        String code = redisUtils.getMailCode(userId);
        SimpleMailMessage mailMessage = MailUtils.setEmailMessage(mail, code);
        javaMailSender.send(mailMessage);
    }


}
